#pragma once

#include "../umlmodel_global.h"

#include <memory>
#include <vector>

#include "NamedElement.h"
#include "RedefinableElement.h"

using std::make_shared;
using std::shared_ptr;
using std::vector;

namespace uml {
class Activity;
class ActivityGroup;
class ActivityNode;
class ActivityPartition;
class InterruptibleActivityRegion;
class RedefinableElement;
class StructuredActivityNode;
class ValueSpecification;

/// <summary>
/// ActivityEdge
/// An ActivityEdge is an abstract class for directed connections between two
/// ActivityNodes.
/// </summary>
class UMLMODEL_EXPORT ActivityEdge : public NamedElement, public RedefinableElement {

public: // Constructors and destructors
    explicit ActivityEdge(const QString& umlType="uml::ActivityEdge");

public: // JsonSerializable override
    void fromJson(const QJsonObject& json, QStringList& errorList) override;
    void toJson(QJsonObject& json) override;

public: // Methods
    /// <summary>
    /// isConsistentWith
    /// </summary>
    bool isConsistentWith(shared_ptr<RedefinableElement> redefiningElement) const override;

public: // Properties
    /// <summary>
    /// activity getter
    /// The Activity containing the ActivityEdge, if it is directly owned by an
    /// Activity.
    /// </summary>
    shared_ptr<Activity> activity() const;

    /// <summary>
    /// activity setter
    /// The Activity containing the ActivityEdge, if it is directly owned by an
    /// Activity.
    /// </summary>
    void setActivity(shared_ptr<Activity> value);

    /// <summary>
    /// guard getter
    /// A ValueSpecification that is evaluated to determine if a token can traverse the
    /// ActivityEdge. If an ActivityEdge has no guard, then there is no restriction on
    /// tokens traversing the edge.
    /// </summary>
    shared_ptr<ValueSpecification> guard() const;

    /// <summary>
    /// guard setter
    /// A ValueSpecification that is evaluated to determine if a token can traverse the
    /// ActivityEdge. If an ActivityEdge has no guard, then there is no restriction on
    /// tokens traversing the edge.
    /// </summary>
    void setGuard(shared_ptr<ValueSpecification> value);

    /// <summary>
    /// inGroups getter
    /// ActivityGroups containing the ActivityEdge.
    /// </summary>
    vector<shared_ptr<ActivityGroup>>& inGroups();

    /// <summary>
    /// inPartitions getter
    /// ActivityPartitions containing the ActivityEdge.
    /// </summary>
    vector<shared_ptr<ActivityPartition>>& inPartitions();

    /// <summary>
    /// inStructuredNode getter
    /// The StructuredActivityNode containing the ActivityEdge, if it is owned by a
    /// StructuredActivityNode.
    /// </summary>
    shared_ptr<StructuredActivityNode> inStructuredNode() const;

    /// <summary>
    /// inStructuredNode setter
    /// The StructuredActivityNode containing the ActivityEdge, if it is owned by a
    /// StructuredActivityNode.
    /// </summary>
    void setInStructuredNode(shared_ptr<StructuredActivityNode> value);

    /// <summary>
    /// interrupts getter
    /// The InterruptibleActivityRegion for which this ActivityEdge is an
    /// interruptingEdge.
    /// </summary>
    shared_ptr<InterruptibleActivityRegion> interrupts() const;

    /// <summary>
    /// interrupts setter
    /// The InterruptibleActivityRegion for which this ActivityEdge is an
    /// interruptingEdge.
    /// </summary>
    void setInterrupts(shared_ptr<InterruptibleActivityRegion> value);

    /// <summary>
    /// redefinedEdges getter
    /// ActivityEdges from a generalization of the Activity containing this ActivityEdge
    /// that are redefined by this ActivityEdge.
    /// </summary>
    vector<shared_ptr<ActivityEdge>>& redefinedEdges();

    /// <summary>
    /// source getter
    /// The ActivityNode from which tokens are taken when they traverse the
    /// ActivityEdge.
    /// </summary>
    shared_ptr<ActivityNode> source() const;

    /// <summary>
    /// source setter
    /// The ActivityNode from which tokens are taken when they traverse the
    /// ActivityEdge.
    /// </summary>
    void setSource(shared_ptr<ActivityNode> value);

    /// <summary>
    /// target getter
    /// The ActivityNode to which tokens are put when they traverse the ActivityEdge.
    /// </summary>
    shared_ptr<ActivityNode> target() const;

    /// <summary>
    /// target setter
    /// The ActivityNode to which tokens are put when they traverse the ActivityEdge.
    /// </summary>
    void setTarget(shared_ptr<ActivityNode> value);

    /// <summary>
    /// weight getter
    /// The minimum number of tokens that must traverse the ActivityEdge at the same
    /// time. If no weight is specified, this is equivalent to specifying a constant
    /// value of 1.
    /// </summary>
    shared_ptr<ValueSpecification> weight() const;

    /// <summary>
    /// weight setter
    /// The minimum number of tokens that must traverse the ActivityEdge at the same
    /// time. If no weight is specified, this is equivalent to specifying a constant
    /// value of 1.
    /// </summary>
    void setWeight(shared_ptr<ValueSpecification> value);

private: // Fields
    /// <summary>
    /// activity
    /// The Activity containing the ActivityEdge, if it is directly owned by an
    /// Activity.
    /// </summary>
    shared_ptr<Activity> activity_;

    /// <summary>
    /// guard
    /// A ValueSpecification that is evaluated to determine if a token can traverse the
    /// ActivityEdge. If an ActivityEdge has no guard, then there is no restriction on
    /// tokens traversing the edge.
    /// </summary>
    shared_ptr<ValueSpecification> guard_;

    /// <summary>
    /// inGroups
    /// ActivityGroups containing the ActivityEdge.
    /// </summary>
    vector<shared_ptr<ActivityGroup>> inGroups_;

    /// <summary>
    /// inPartitions
    /// ActivityPartitions containing the ActivityEdge.
    /// </summary>
    vector<shared_ptr<ActivityPartition>> inPartitions_;

    /// <summary>
    /// inStructuredNode
    /// The StructuredActivityNode containing the ActivityEdge, if it is owned by a
    /// StructuredActivityNode.
    /// </summary>
    shared_ptr<StructuredActivityNode> inStructuredNode_;

    /// <summary>
    /// interrupts
    /// The InterruptibleActivityRegion for which this ActivityEdge is an
    /// interruptingEdge.
    /// </summary>
    shared_ptr<InterruptibleActivityRegion> interrupts_;

    /// <summary>
    /// redefinedEdges
    /// ActivityEdges from a generalization of the Activity containing this ActivityEdge
    /// that are redefined by this ActivityEdge.
    /// </summary>
    vector<shared_ptr<ActivityEdge>> redefinedEdges_;

    /// <summary>
    /// source
    /// The ActivityNode from which tokens are taken when they traverse the
    /// ActivityEdge.
    /// </summary>
    shared_ptr<ActivityNode> source_;

    /// <summary>
    /// target
    /// The ActivityNode to which tokens are put when they traverse the ActivityEdge.
    /// </summary>
    shared_ptr<ActivityNode> target_;

    /// <summary>
    /// weight
    /// The minimum number of tokens that must traverse the ActivityEdge at the same
    /// time. If no weight is specified, this is equivalent to specifying a constant
    /// value of 1.
    /// </summary>
    shared_ptr<ValueSpecification> weight_;

};

} // namespace uml
